 sbtl 'xdos read/write routines revised' 
* org $d400 ; ** moved to xrw file **
****************************
*                         *
*     critical timing     *
*   requires page bound   *
*   considerations for    *
*      code and data      *
*     code-----      *
*   virtually the entire  *
*     'write' routine     *
*      must not cross     *
*     page boundaries.    *
*  critical branches in   *
*  the 'write', 'read',   *
*  and 'read adr' subrs   *
*  which must not cross   *
*  page boundaries are    *
*  noted in comments.     *
*                         *
****************************
*                         *
*         equates         *
*                         *
maxcmd equ 4 ;commands 0-3 only
wtemp equ $3a 
midnib1 equ wtemp+1
midnib2 equ wtemp+2
lstnib equ wtemp+3
slotz equ wtemp+4
yend equ wtemp+5
dhpcmd equ $42 
unitnum equ $43
buf equ $44 
bloknml equ $46
bloknmh equ bloknml+1
*
dvmot equ $e8 
*
************************
*                      *
*    device address    *
*     assignments      *
*                      *
************************
phaseoff equ $c080 ;stepper phase off.
*phaseon equ $c081 ;stepper phase on.
q6l equ $c08c ;q7l,q6l=read
q6h equ $c08d ;q7l,q6h=sense wprot
q7l equ $c08e ;q7h,q6l=write
q7h equ $c08f ;q7h,q6h=write store
****************************************
*
* equates for rwts and block
*
****************************************
motoroff equ $c088
motoron equ $c089
drv0en equ $c08a
*drv1en equ $c08b
ibderr equ $27 
ibwper equ $2b 
ibnodrv equ $28 
 page
************************
*                      *
*       block i/o      * 
*                      * 
************************
blockio cld ;this must be first as it is an id value
 jsr rsetphse
 skp 1
* this is patch 76 part 1.  part 2 is in xrw2.
* this is patch 77, use to be 'lda q7l+14,x'.
 skp 1
 lda q7l,x ;turn off write enable please!!!
 skp 1
* (pad is just spare bytes but the number is critical for page
pad equ >* ;alignment of tables later.)
 ds $09-pad,$ea ;fill pad w/nops
 jsr docheck
 bcs badblk ;branch if block # is out of range
blkio1 ldy #$5
trksec asl a
 rol ibtrk
 dey
 bne trksec
 asl a 
 bcc trksc1 
 ora #$10 ;adjust for upper 4 blks of trk. 
trksc1 lsr a
 lsr a
 lsr a 
 lsr a 
 pha ;save sector#
 jsr regrwts
 pla ;restore sector #
 bcs quit ;branch if error encountered. 
 inc buf+1
 adc #2 
 jsr regrwts ;get second half of block. 
 dec buf+1
quit lda ibstat
 rts
*
badblk lda #ibderr ;i/o error
 sec
 rts
 page
**************************
*                        *
*     read/write a       *
*   track and sector     *
*                        *
**************************
*
regrwts ldy #1  ;retry count
 sty seekcnt ;only one recalibrate per call
 sta ibsect
 lda unitnum  ;get slot # for this operation
 and #$70
 sta slotz
 jsr chkprev ;make sure other drives in other slots are stopped.
*
* now check if the motor is on, then start it
*
 jsr chkdrv ;set zero flag if motor stopped
 php ;save test results
 lda #dvmot
 sta montimeh
 lda unitnum ;determine drive one or two
 cmp iobpdn ;same drive used before?
 sta iobpdn ;save it for next time
 php  ;keep results of compare
 asl a  ;get drive number into carry
 lda motoron,x  ;turn on the drive
 bcc drivsel  ;branch if drive 1 selected
 inx  ;select drive 2
drivsel lda drv0en,x
 plp  ;was it same drive?
 beq ok
 plp  ;must indicate drive off by setting zero flag)
 ldy #7  ;delay 150 ms before stepping
drvwait jsr mswait  ;(on return a=0)
 dey
 bne drvwait
 php  ;now zero flag set
ok lda dhpcmd ;make sure this command needs seeking.
 beq ok1 ;branch if status check.
 lda ibtrk ;get destination track
 jsr myseek ;and go to it.
*now at the desired track.  was the motor
* on to start with?
ok1 plp ;was motor on?
 bne trytrk ;if so, don't delay, get it today!
*
* motor was off, wait for it to speed up.
*
motof lda #1  ;wait exactly 100 us for each count in montime
 jsr mswait 
 lda montimeh 
 bmi motof ;count up to 0000
 page
****************************************
*
* motor should be up to speed.
* if it still looks stopped then 
* the drive is not present.
*
****************************************
 jsr chkdrv ;is drive present?
 beq hndlerr ;branch if no drive 
*
* now check: if it is not the format disk command,
*  locate the correct sector for this operation.
*
trytrk lda dhpcmd ;get command code #
 beq statcmd ;if $00, then status command. 
 lsr a ;set carry=1 for read, 0 for write
 bcs trytrk2 ;must prenibblize for write.
 jsr prenib16
trytrk2 ldy #$40 ;only 64 retries of any kind
 sty retrycnt
tryadr ldx slotz ;get slot num into x-reg
 jsr rdadr16 ;read next address field
 bcc rdright ;if read it right, hurrah!
tryadr2 equ * 
 dec retrycnt ;another mistaek!!
 bpl tryadr ; well, let it go this time.,
 lda #ibderr ;anticipate a bad drive error
 dec seekcnt ;only recalibrate once!
 bne hndlerr ;tried to recalibrate a second time, error!
 lda curtrk
 pha ;save track we really want
 asl a 
 adc #$10 ;pretend track is 8>curtrk 
 ldy #$40
 sty retrycnt ;reset retrys to 64 max.
 bne recal1 ;branch always 
* 
* have now read an address field correctly.
* make sure this is the track, sector, and volume desired.
rdright ldy track ;on the right track?
 cpy curtrk
 beq rttrk ;if so, good
* recalibrating from this track
 lda curtrk ;preserve destination track
 pha
 tya   
 asl a ;(washing machine fix!)
recal1 jsr settrk
 pla
 jsr myseek
 bcc tryadr ;go ahead and recalibrate
 page
*
* drive is on right track, check volume mismatch
*
rttrk lda sect ;check if this is the right sector
 cmp ibsect
 bne tryadr2 ;no, try another sector
 lda dhpcmd  ;read or write?
 lsr a  ;the carry will tell.
 bcc writ ;carry was set for read operation,
 jsr read16 ;cleared for write
 bcs tryadr2 ;carry set upon return if bad read
* 
alldone equ * ;was clc
 lda #$0 ;no error
 dfb $d0 ;branch never (skip 1 byte)
hndlerr sec ;indicate an error
aldone1 sta ibstat ;give him error#
 ldx slotz ;get the slot offset
 lda motoroff,x ;turn it off...
 rts ;all finished! 
*
writ jsr write16 ;write nybbles now
statdne bcc alldone ;if no errors.
 lda #ibwper ;disk is write protected!!
 bne hndlerr ;branch always 
* 
statcmd ldx slotz 
 lda q6h,x ;test for write protected. 
 lda q7l,x
 rol a ;write protect-->carry-->bit 0=1
 lda q6l,x ;keep in read mode...
 jmp statdne ;branch always taken.
 page
*
* this is the 'seek' routine
*  seeks track 'n' in slot #x/$10
* if drivno is negative, on drive 0
* if drivno is positive, on drive 1
*
myseek asl a ;assume two phase stepper.
 sta track ;save destination track(*2)
 jsr alloff ;turn all phases off to be sure.
 jsr drvindx  ;get index to previous track for current drive
 lda drv0trk,x
 sta curtrk ;this is where i am
 lda track ;and where i'm going to
 sta drv0trk,x
 jsr seek ;go there!
alloff ldy #3  ;turn off all phases before returning
nxoff tya  ;(send phase in acc.)
 jsr clrphase  ;carry is clear, phases shold be turned off
 dey
 bpl nxoff
 lsr curtrk  ;divide back down
 clc
 rts  ;all off... now it's dark
 page
**************************
*                        *
*  fast seek subroutine  *
**************************
*                        *
*    on entry ----   *
*                        *
*  x-reg holds slotnum   *
*         times $10.     *
*                        *
*  a-reg holds desired   *
*         halftrack.     *
*         (single phase) *
*                        *
*  curtrk holds current  *
*          halftrack.    *
*                        *
*    on exit -----   *
*                        *
*  a-reg uncertain.      *
*  y-reg uncertain.      *
*  x-reg undisturbed.    *
*                        *
*  curtrk and trkn hold  *
*      final halftrack.  *
*                        *
*  prior holds prior     *
*    halftrack if seek   *
*    was required.       *
*                        *
*  montimel and montimeh *
*    are incremented by  *
*    the number of       *
*    100 usec quantums   *
*    required by seek    *
*    for motor on time   *
*    overlap.            *
*                        *
* --- variables used --- *
*                        *
*  curtrk, trkn, count,  *
*    prior, slottemp     *
*    montimel, montimeh  *
*                        *
**************************
seek sta trkn ;save target track
 cmp curtrk ;on desired track?
 beq setphase ;yes,energize phase and return
 lda #$0
 sta trkcnt ;halftrack count.
seek2 lda curtrk ;save curtrk for
 sta prior ;delayed turnoff.
 sec
 sbc trkn ;delta-tracks.
 beq seekend ;br if curtrk=destination
 bcs out ;(move out, not in)
 eor #$ff ;calc trks to go.
 inc curtrk ;incr current track (in).
 bcc mintst ;(always taken)
out adc #$fe ;calc trks to go.
 dec curtrk ;decr current track (out).
mintst cmp trkcnt
 bcc maxtst ; and 'trks moved'.
 lda trkcnt
maxtst cmp #$9
 bcs step2 ;if trkcnt>$8 leave y alone (y=$8).
 tay ;else set acceleration index in y
 sec
step2 jsr setphase
 lda ontable,y ;for 'ontime'.
 jsr mswait ;(100 usec intervals)
 lda prior
 clc  ;for phaseoff
 jsr clrphase ;turn off prior phase
 lda offtable,y ; then wait 'offtime'.
 jsr mswait ;(100 usec intervals)
 inc trkcnt ; 'tracks moved' count.
 bne seek2 ;(always taken)
seekend jsr mswait ;settle 25 msec
 clc  ;set for phase off
setphase lda curtrk ;get current track
clrphase and #3 ;mask for 1 of 4 phases
 rol a ;double for phaseon/off index
 ora slotz 
 tax
 lda phaseoff,x ;turn on/off one phase
 ldx slotz ;restore x-reg
 rts ;and return
 page
*
**************************
*                        *
*     7-bit to 6-bit     *
*    'deniblize' tabl    *
*   (16-sector format)   *
*                        *
*      valid codes       *
*    $96 to $ff only.    *
*                        *
*  codes with more than  *
*  one pair of adjacent  *
*   zeroes or with no    *
*  adjacent ones (except *
*   bit 7) are excluded. *
*                        *
*  nibls in the ranges   *
*  of $a0-$a3, $c0-$c7,  *
*  $e0-$e3 are used for  *
*  other tables since no *
*  valid nibls are in    *
*  these ranges.         *
**************************
* 
dnibl equ *-$96 
 dfb $00,$04 
 dfb $ff,$ff,$08,$0c
 dfb $ff,$10,$14,$18
twobit3 dfb $00,$80,$40,$c0 ;used in fast prenib as lookup for 2-bit quantities. 
 dfb $ff,$ff,$1c,$20 
 dfb $ff,$ff,$ff,$24 
 dfb $28,$2c,$30,$34 
 dfb $ff,$ff,$38,$3c 
 dfb $40,$44,$48,$4c 
 dfb $ff,$50,$54,$58 
 dfb $5c,$60,$64,$68 
twobit2 dfb $00,$20,$10,$30 ;used in fast prenib. 
endmrks dfb $de,$aa,$eb,$ff ;table using 'unused' nibls ($c4,$c5,$c6,$c7) 
 dfb $ff,$ff,$ff,$6c 
 dfb $ff,$70,$74,$78 
 dfb $ff,$ff,$ff,$7c 
 dfb $ff,$ff,$80,$84 
 dfb $ff,$88,$8c,$90 
 dfb $94,$98,$9c,$a0 
twobit1 dfb $00,$08,$04,$0c ;used in fast prenib. 
 dfb $ff,$a4,$a8,$ac 
 dfb $ff,$b0,$b4,$b8 
 dfb $bc,$c0,$c4,$c8 
 dfb $ff,$ff,$cc,$d0 
 dfb $d4,$d8,$dc,$e0 
 dfb $ff,$e4,$e8,$ec 
 dfb $f0,$f4,$f8,$fc 
*
 page
;   page align the following tables.
***************************
*                         *
*     6-bit to 2-bit      *
*   conversion tables.    *
*                         *
* dnibl2 abcdef-->0000fe  *
* dnibl3 abcdef-->0000dc  *
* dnibl4 abcdef-->0000ba  *
*                         *
***************************
*                         *
*     6-bit to 7-bit      *
*  nibl conversion table  *
*                         *
*   codes with more than  *
*   one pair of adjacent  *
*    zeroes or with no    *
*   adjacent ones (except *
*     b7) are excluded.   *
*                         *
***************************
dnibl2 dfb 0
dnibl3 dfb 0
dnibl4 dfb 0
nibl dfb $96,2,0,0,$97
 dfb 1,0,0,$9a,3,0,0,$9b
 dfb 0,2,0,$9d,2,2,0,$9e
 dfb 1,2,0,$9f,3,2,0,$a6
 dfb 0,1,0,$a7,2,1,0,$ab
 dfb 1,1,0,$ac,3,1,0,$ad
 dfb 0,3,0,$ae,2,3,0,$af
 dfb 1,3,0,$b2,3,3,0,$b3
 dfb 0,0,2,$b4,2,0,2,$b5
 dfb 1,0,2,$b6,3,0,2,$b7
 dfb 0,2,2,$b9,2,2,2,$ba
 dfb 1,2,2,$bb,3,2,2,$bc
 dfb 0,1,2,$bd,2,1,2,$be
 dfb 1,1,2,$bf,3,1,2,$cb
 dfb 0,3,2,$cd,2,3,2,$ce
 dfb 1,3,2,$cf,3,3,2,$d3
 dfb 0,0,1,$d6,2,0,1,$d7
 dfb 1,0,1,$d9,3,0,1,$da
 dfb 0,2,1,$db,2,2,1,$dc
 dfb 1,2,1,$dd,3,2,1,$de
 dfb 0,1,1,$df,2,1,1,$e5
 dfb 1,1,1,$e6,3,1,1,$e7
 dfb 0,3,1,$e9,2,3,1,$ea
 dfb 1,3,1,$eb,3,3,1,$ec
 dfb 0,0,3,$ed,2,0,3,$ee
 dfb 1,0,3,$ef,3,0,3,$f2
 dfb 0,2,3,$f3,2,2,3,$f4
 dfb 1,2,3,$f5,3,2,3,$f6
 dfb 0,1,3,$f7,2,1,3,$f9
 dfb 1,1,3,$fa,3,1,3,$fb
 dfb 0,3,3,$fc,2,3,3,$fd
 dfb 1,3,3,$fe,3,3,3,$ff
 page
*
nbuf2 ds $56,0 ;nibl buffer for read/write of low 2-bits of each byte.
*
* 
ibtrk dfb $00 
ibsect dfb $00 
ibstat dfb $00 
iobpdn dfb $00 
curtrk dfb $00 
drv0trk equ *-2 
 dfb 0,0,0,0,0,0,0 ;for slots 1 thru 7 
 dfb 0,0,0,0,0,0,0 ;drives 1 & 2
retrycnt ds 1,0 
seekcnt ds 1,0 
*
************************
*                      *
*    readadr----   *
*                      *
************************
count equ * ;'must find' count.
last ds 1,0 ;'odd bit' nibls.
csum ds 1,0 ;used for address header cksum
csstv ds 4,0 ;four bytes,
*       checksum, sector, track, and volume.
sect equ csstv+1
track equ csstv+2 
volume equ csstv+3 
*
trkcnt equ count ;halftrks moved count.
prior ds 1,0 
trkn ds 1,0 
*
************************
*                      *
*    mswait ----   *
*                      *
************************
montimel equ csstv+2 ;motor-on time
montimeh equ montimel+1 ;counters.
*
 page
**************************
*                        *
*  phase on-, off-time   *
*   tables in 100-usec   *
*   intervals. (seek)    *
*                        *
**************************
ontable dfb 1,$30,$28
 dfb $24,$20,$1e
 dfb $1d,$1c,$1c
offtable dfb $70,$2c,$26
 dfb $22,$1f,$1e
 dfb $1d,$1c,$1c
* 
**************************
*                        *
*   mswait subroutine    *
*                        *
**************************
*                        *
*  delays a specified    *
*   number of 100 usec   *
*   intervals for motor  *
*   on timing.           *
*                        *
*    on entry ----   *
*                        *
*  a-reg: holds number   *
*        of 100 usec     *
*        intervals to    *
*        delay.          *
*                        *
*    on exit -----   *
*                        *
*  a-reg: holds $00.     *
*  x-reg: holds $00.     *
*  y-reg: unchanged.     *
*  carry: set.           *
*                        *
*  montimel, montimeh    *
*   are incremented once *
*   per 100 usec interval*
*   for moton on timing. *
*                        *
*    assumes ----    *
*                        *
*   1 usec cycle time    *
*                        *
**************************
mswait ldx #$11
msw1 dex delay 86 usec.
 bne msw1
 inc montimel
 bne msw2 double-byte
 inc montimeh   increment.
msw2 sec
 sbc #$1 done 'n' intervals?
 bne mswait (a-reg counts)
 rts
